package com.xuecheng.content.service.jobhandler;

import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.content.feignclient.CourseIndex;
import com.xuecheng.content.feignclient.SearchServiceClient;
import com.xuecheng.content.mapper.CoursePublishMapper;
import com.xuecheng.content.model.po.CoursePublish;
import com.xuecheng.content.service.CoursePublishService;
import com.xuecheng.messagesdk.model.po.MqMessage;
import com.xuecheng.messagesdk.service.MessageProcessAbstract;
import com.xuecheng.messagesdk.service.MqMessageService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

import java.io.File;

/**
 * 课程发布的任务类
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class CoursePublishTask extends MessageProcessAbstract {

    private final CoursePublishService coursePublishService;

    private final SearchServiceClient searchServiceClient;

    private final CoursePublishMapper coursePublishMapper;

    /**
     * 任务调度入口
     *
     * @throws Exception
     */
    @XxlJob("CoursePublishJobHandler")
    public void coursePublishJobHandler() throws Exception {
        // 分片参数
        int shardIndex = XxlJobHelper.getShardIndex(); // 执行器的序号，从0开始
        int shardTotal = XxlJobHelper.getShardTotal(); // 执行器总数
        log.debug("shardIndex=" + shardIndex + ",shardTotal=" + shardTotal);
        // 参数:分片序号、分片总数、消息类型、一次最多取到的任务数量、一次任务调度执行的超时时间
        // 调用抽象类的方法执行任务
        process(shardIndex, shardTotal, "course_publish", 30, 60);
    }


    /**
     * 执行课程发布任务的逻辑 如果抛出异常表示任务执行失败
     *
     * @param mqMessage 执行任务内容
     * @return 返回true 表示任务执行成功，false表示任务执行失败
     */
    @Override
    public boolean execute(MqMessage mqMessage) {
        // 拿到课程id
        Long courseId = Long.parseLong(mqMessage.getBusinessKey1());

        // 课程静态的页面上传到minion中
        generateCourseHtml(mqMessage, courseId);

        // 向redis中写入缓存
        saveCourseCache(mqMessage, courseId);

        // 向es表中写入数据
        saveCourseIndex(mqMessage, courseId);

        // 返回true表示任务执行成功
        return false;
    }

    /**
     * 生成课程静态化页面并上传至文件系统
     *
     * @param mqMessage 执行任务的内容
     * @param courseId  课程id
     */
    private void generateCourseHtml(MqMessage mqMessage, long courseId) {
        // 先获取消息id
        Long taskId = mqMessage.getId();
        // 查询数据库取出该阶段的任务状态
        MqMessageService mqMessageService = this.getMqMessageService();

        // 做任务幂等性处理
        int stageOne = mqMessageService.getStageOne(taskId);
        if (stageOne > 0) {
            log.debug("生成课程静态化页面并上传至文件系统，任务已经完成，无需处理");
            return;
        }

        // 开始执行课程静态化
        File file = coursePublishService.generateCourseHtml(courseId);
        if (file == null) {
            XueChengPlusException.cast("生成课程静态化页面为空");
        }

        // 将file文件上传到minion
        coursePublishService.uploadCourseHtml(courseId, file);

        // 任务状态完成写任务状态为完成
        mqMessageService.completedStageOne(taskId);
    }

    /**
     * 将课程信息写入索引表
     *
     * @param mqMessage 执行任务的内容
     * @param courseId  课程id
     */
    private void saveCourseIndex(MqMessage mqMessage, long courseId) {
        // 先获取消息id
        Long taskId = mqMessage.getId();
        // 查询数据库取出该阶段的任务状态
        MqMessageService mqMessageService = this.getMqMessageService();

        // 做任务幂等性处理
        int stageTwo = mqMessageService.getStageTwo(taskId);
        if (stageTwo > 0) {
            log.debug("将课程信息写入索引表，任务已经完成，无需处理");
            return;
        }

        // 查询课程信息，调用搜索服务添加索引接口
        // 从课程发布表查询课程信息
        CoursePublish coursePublish = coursePublishMapper.selectById(courseId);
        CourseIndex courseIndex = new CourseIndex();
        BeanUtils.copyProperties(coursePublish, courseIndex);
        // 远程调用
        Boolean add = searchServiceClient.add(courseIndex);
        if (!add){
            XueChengPlusException.cast("远程调用搜索服务添加课程信息失败");
        }

        // 完成本阶段的任务
        mqMessageService.completedStageTwo(taskId);
    }

    /**
     * 将课程信息缓存至redis
     *
     * @param mqMessage 执行任务的内容
     * @param courseId  课程id
     */
    public void saveCourseCache(MqMessage mqMessage, long courseId) {
        // 先获取消息id
        Long taskId = mqMessage.getId();
        // 查询数据库取出该阶段的任务状态
        MqMessageService mqMessageService = this.getMqMessageService();

        // 做任务幂等性处理
        int stageThree = mqMessageService.getStageThree(taskId);
        if (stageThree > 0) {
            log.debug("将课程信息写入缓存，任务已经完成，无需处理");
        }

        // 开始执行课程静态化

        // 任务状态完成写任务状态为完成
        mqMessageService.completedStageTwo(taskId);
    }
}
